package cc.togetherit.jcrawler.fetch;

import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cc.togetherit.jcrawler.checkRepeat.RepeatCheck;
import cc.togetherit.jcrawler.dataPool.CrawlerPool;

public abstract class AbstractFetchEngine implements FetchEngine, Runnable {
    public CrawlerPool<String> downPool;
    public CrawlerPool<FetchRequest> fetchPool;
    public CrawlerPool<FetchRequest> parsePool;
    private FetchConfig fetchConfig;
    private boolean isstop = false;
    private RepeatCheck check;

    private ArrayList<Pattern> fetchPatternList = new ArrayList<Pattern>();
    private ArrayList<Pattern> parsePatternList = new ArrayList<Pattern>();

    public AbstractFetchEngine(CrawlerPool<String> downPool, CrawlerPool<FetchRequest> fetchPool, CrawlerPool<FetchRequest> parsePool, RepeatCheck check) {
        super();
        this.downPool = downPool;
        this.fetchPool = fetchPool;
        this.parsePool = parsePool;
        this.check = check;
    }


    public void run() {
        start();

    }

    public RepeatCheck getCheck() {
        return check;
    }



    public void setCheck(RepeatCheck check) {
        this.check = check;
    }



    public FetchConfig getFetchConfig() {
        return fetchConfig;
    }



    public void setFetchConfig(FetchConfig fetchConfig) {
        this.fetchConfig = fetchConfig;
    }



    public CrawlerPool<String> getDownPool() {
        return downPool;
    }

    public void setDownPool(CrawlerPool<String> downPool) {
        this.downPool = downPool;
    }

    public CrawlerPool<FetchRequest> getFetchPool() {
        return fetchPool;
    }

    public void setFetchPool(CrawlerPool<FetchRequest> fetchPool) {
        this.fetchPool = fetchPool;
    }

    public CrawlerPool<FetchRequest> getParsePool() {
        return parsePool;
    }

    public void setParsePool(CrawlerPool<FetchRequest> parsePool) {
        this.parsePool = parsePool;
    }

    public boolean isIsstop() {
        return isstop;
    }

    public void setIsstop(boolean isstop) {
        this.isstop = isstop;
    }


    public ArrayList<Pattern> getCrawlPatternList() {
        return fetchPatternList;
    }


    public void setCrawlPatternList(ArrayList<Pattern> crawlPatternList) {
        this.fetchPatternList = crawlPatternList;
    }


    public void start() {

        initRegexConfig();
        while (!isstop) {
            FetchRequest t = fetchPool.consume();
            if (t == null) {
                t = fetchPool.consume();
                if (t == null) {
                    isstop = true;
                    continue;
                }
            }
            FetchResponse response = fetch(t);
            parseContent(t);
            filter(response);
        }

    }


    private void initRegexConfig() {
        Map<String, Integer> regex = this.getFetchConfig().getFetchRegex();
        Set<String> sets = null;
        if (regex != null) {
            sets = regex.keySet();
            for (String p : sets) {
                fetchPatternList.add(Pattern.compile(p, Pattern.CASE_INSENSITIVE));
            }
        }

        regex = this.getFetchConfig().getParseRegex();
        if (regex != null) {
            sets = regex.keySet();
            for (String p : sets) {
                parsePatternList.add(Pattern.compile(p, Pattern.CASE_INSENSITIVE));
            }
        }
    }

    private void parseContent(FetchRequest t) {
        if (this.shouldParsed(t.getUrl())) {
            parsePool.produce(t);
        }
    }

    private void filter(FetchResponse response) {
        Set<String> sets = response.getLinks();
        for (String link : sets) {
            if (!visited(link) && shouldFetched(link)) {
                check.setvisited(link);
                downPool.produce(link);
            };
        }
    }

    public abstract boolean visited(String link);



    public boolean shouldParsed(String url) {



        if (parsePatternList == null || parsePatternList.size() == 0) {
            return true;
        }
        Matcher m;
        for (Pattern pattern : parsePatternList) {
            m = pattern.matcher(url);
            if (m.find()) {
                m = null;
                return true;
            }
            m = null;
        }
        return false;


    }


    public void stop() {


    }
}
